home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / PPC source / cg6 < prev    next >
Text File  |  1999-01-14  |  53KB  |  2,154 lines

  1. PPC?
  2. [IF]
  3. false    constant    debug?
  4. [ELSE]
  5. false    constant    debug?
  6. [THEN]
  7.  
  8.  
  9.  
  10. \    ===============  SUNDRY INDIVIDUAL HANDLERS  ==================
  11.  
  12. OD    valOD
  13.  
  14. PPC? not
  15. [IF]
  16.  
  17. : 68kReg>PPC  { reg# \ regType -- ppc-reg# }
  18.     reg# $ E0 and  -> regType    \ 0 Dn, $20 FPn, $40 An, $60 already a PPC reg
  19.     reg# $ 1F and  -> reg#
  20.  
  21.     regType
  22.     CASE[    $ 60    ]=>            reg#    \ already a PPC reg# - leave unchanged
  23.           
  24.         [    0        ]=>                    \ Dn on 68k
  25.             reg#
  26.             SELECT[    1    ]=>        0
  27.                     [    3    ]=>        I_reg
  28.                   DEFAULT=>        drop  0
  29.             ]SELECT
  30.             
  31.         [    $ 20    ]=>
  32.         
  33.         [    $ 40    ]=>                    \ An on 68k
  34.             reg#
  35.             SELECT[    2    ]=>        obj_base_reg
  36.                   [    3    ]=>        mainData_reg
  37.                   [    4    ]=>        mainData_reg
  38.                   [    5    ]=>        modData_reg
  39.                   DEFAULT=>        db drop  0
  40.             ]SELECT
  41.  
  42.         DEFAULT=>    db
  43.     ]CASE
  44. ;
  45.  
  46. [THEN]
  47.  
  48.  
  49. : ^EXTRA_INFO  { cfa -- addr }
  50.     cfa c@  $ FF =
  51.     IF  2  ELSE  4  THEN  cfa +  ;
  52.  
  53.  
  54. PPC?
  55. [IF]
  56.  
  57. : genAddr  { base-reg displ ind# -- }
  58.  
  59. (*    Rather similar to litaddr_h.  Called via (OBJ) when we are compiling
  60.     an inline method, and generating the object address.  The "base-reg" may
  61.     be negative, in which case the "displ" is an absolute address.
  62.     I suspect ind# will always be zero on the PPC, so I'll trap it if it's
  63.     not.
  64. *)
  65.     ind# if $ deadbeef $ 129 db 2drop then
  66.     
  67.     base-reg 0<
  68.     IF        displ b&d
  69.     ELSE    base-reg  displ
  70.     THEN
  71.     (litAddr)
  72. ;
  73.  
  74. [ELSE]        \ only change is to add 68kReg>PPC call.
  75.  
  76. : genAddr  { base-reg displ ind# -- }
  77.  
  78.     ind# if $ deadbeef $ 100 db 2drop then
  79.     base-reg 0<
  80.     IF        displ b&d
  81.     ELSE    base-reg 68kReg>PPC
  82.             displ
  83.     THEN
  84.     (litAddr)
  85. ;
  86.  
  87. [THEN]
  88.  
  89.  
  90. : genXAddr { ixwid ixoffs base-reg displ local-displ ind# flags \ lim -- }
  91.  
  92. (*    Called by (IX) when we are compiling an in-line method, and generating
  93.     the address of an indexed element of the current object.
  94.     The base-reg, displ and ind refers to the obj addr.  ixoffs is the offset
  95.     to the indexed area, if we know it.  This will happen if the obj
  96.     is a straight object or an ivar (ivars are generic to a class, but
  97.     each one has a fixed ixoffs).  In these cases we can absorb the ixoffs
  98.     at compile time.  If, however, the "obj" is self or super, then we won't
  99.     know the ixoffs at compile time, since at different points in the class
  100.     hierarchy the ixoffs is different.  It is always located at run time
  101.     2 bytes after the class pointer (this is changed from 68k).  In this
  102.     case we will pass in a negative "ixoffs".
  103.     As for hGenaddr, the "base-reg" may be negative, which means that the
  104.     "displ" is actually an absolute addr.
  105. *)
  106.  
  107.     -1 -> lim
  108.     base-reg 0<
  109.     IF    displ ixoffs + 4- @  -> lim  THEN
  110.  
  111.     ixoffs 0<
  112.     IF    " (^base) 2- dup w@x +"  evaluate
  113.         range_check?
  114.         IF  " 2dup 4- @ u> ?trap"  evaluate  THEN
  115.     ELSE
  116.         base-reg  displ ixoffs + local-displ +  ind#  genAddr
  117.                 \ note - we can't just add the local-displ if ind# is nonzero,
  118.                 \  but I think on the PPC we can arrange for it to always be
  119.                 \  zero (and we'll get rid of it altogether eventually).
  120.  
  121. \ run time: ( index ^indexed-area )
  122.  
  123.         range_check?
  124.         IF
  125.             lim 0<
  126.             IF
  127.                 " 2dup 4- @ u> ?trap"
  128.             ELSE            \ we have the object available
  129.                 " over" evaluate        \ get index
  130.                 lim  postpone literal
  131.                 " u> ?trap"
  132.             THEN
  133.             evaluate
  134.         THEN
  135.     THEN
  136.  
  137.     swap_cstk
  138.  
  139.     debug? if
  140.         ." about to gen indexed addr - cstk:" printall: cstk
  141.     then
  142.     ixwid 1 > IF  ixwid  postpone literal  postpone *  THEN
  143.     postpone +
  144.     debug? if
  145.         ." afterwards - cstk:" printall: cstk
  146.     then
  147. ;
  148.  
  149.  
  150. : hStkObj    \ ( -- base-reg displ )
  151.  
  152. (*    Sets up for an early bind to an object whose
  153.     (data) addr is on the stack at run time.  We also handle object
  154.     pointers this way, by first compiling a fetch of the objPtr
  155.     to the stack, and relying on our optimization to improve the code.
  156.     Rather than leaving the ^obj on the stack, we return the addressing
  157.     info back to the CLASS code.  This is because we may be binding to an
  158.     inline method which uses OBJ anywhere - more than once, even.
  159. *)
  160.     debug? if
  161.         ." hStkObj called - cstk:"  printall: cstk cr
  162.     then
  163.     1 operands
  164.     reftype: opnd1 gprRef <>  IF  210 die  THEN        \ "can't bind to that"
  165. \    opnd1 get_to_reg? drop
  166.     gpr: opnd1
  167. [ ppc? not ]
  168. [if]
  169.     $ 60 or        \ the $60 marks this as a PPC reg, when target
  170.                 \  compiling only
  171. [then]
  172.     0
  173. \ Note: we mustn't  free: opnd1  here, since the upcoming early_bind
  174. \  call may execute inline code which allocates a reg!
  175. ;
  176.  
  177.  
  178. : CREATE_H    litAddr_h  ;
  179. : BUILDS_H    4+  litAddr_h  ;
  180. : OBJ_H        litAddr_h  ;        \ ptr points to obj's data, 12 bytes after
  181.                                 \  the obj header
  182.  
  183.  
  184. ppc? not
  185. [IF]
  186.  
  187. : CLASS_H    db  ;        \ mustn't get called on the 68k - ppc_obj is what gets
  188.                         \  called.  The proper PPC class_h is defined in qpClass.
  189.  
  190. [THEN]
  191.  
  192.  
  193. : DO_FETCH  { len flags \ reg#  -- }
  194.  
  195.     1 operands
  196.     debug? if
  197.         ." do_fetch - opnd1: " cr print: opnd1
  198.     then
  199.  
  200.     reftype: opnd1  gprNameRef =
  201.     IF    gprRef >refType: opnd1
  202.         opnd1 push  EXIT
  203.     THEN
  204.  
  205.     addr: opnd1  get_to_gpr? drop
  206.  
  207.     clear: theOD
  208.     otFetch put: ivar> opType    in theOD
  209.     len        put: ivar> len        in theOD
  210.     flags    put: ivar> flags    in theOD
  211.  
  212.     gpr: opnd1    dup -> reg#    >Agpr: theOD
  213.     0                        >Blit: theOD
  214.  
  215.     cascade&match?
  216.     
  217.     debug? if
  218.         ." matched? " dup if ." yes" else ." no" then cr
  219.     then
  220.     
  221.     NIF    1 results
  222.         theOD copyWithoutCDP: GPRs
  223.         compile: GPRs
  224.         free: opnd1
  225.     THEN
  226.  
  227.     res1 push
  228. ;
  229.  
  230.  
  231. : DO_FP_FETCH  { len \ reg# -- }
  232.     1 operands
  233.  
  234.     debug? if
  235.         ." do_FP_fetch - opnd1: " cr print: opnd1
  236.     then
  237.  
  238.     reftype: opnd1  fprNameRef =
  239.     IF    fprRef >refType: opnd1
  240.         opnd1 fpush  EXIT
  241.     THEN
  242.  
  243.     addr: opnd1  get_to_gpr? drop
  244.  
  245.     clear: theOD
  246.     otFPfetch    put: ivar> opType in theOD
  247.     len            put: ivar> len in theOD
  248.  
  249.     gpr: opnd1    dup -> reg#    >Agpr: theOD
  250.     0                        >Blit: theOD
  251.  
  252.     cascade&match?
  253.     
  254.     debug? if
  255.         ." matched? " dup if ." yes" else ." no" then cr
  256.     then
  257.  
  258.     NIF    1 fresults
  259.         theOD copyWithoutCDP: FPRs
  260.         compile: FPRs
  261.         free: opnd1
  262.     THEN
  263.     res1 fpush
  264. ;
  265.  
  266.  
  267. (* RECORD_GPR_STORE puts an entry for the passed-in OD in stored_GPRs,
  268. in case we can optimize out a subsequent fetch of the same location
  269. (i.e. in the case where the stored value is still sitting in the reg
  270. we stored it from).
  271.  
  272. We used to simply change the op in the stored GPR to a fetch, so it
  273. could match any subsequent fetch of that location.  But it's better
  274. to keep a separate record in stored_GPRs, and check there for a match.
  275. This has the same effect, but means we don't have to clobber the prev
  276. info in the reg's OD - we might be able to match on the op that
  277. generated the value.  Even if the GPR's type is otUnknown, although 
  278. we won't be able to match on it, we still might be able to optimize
  279. out a subsequent fetch of the same location we're storing into.  So
  280. we change the type to otUnkStored, which will mean we hang on to it
  281. a bit longer than otUnknown (which are up for grabs as soon as we need
  282. to allocate a free reg).
  283.     
  284. We also clobber any fetch of the target location that might
  285. still be sitting around in a reg, since that value isn't valid any more.
  286.  
  287. Special note: we don't record partial word stores, since in the
  288. general case, a fetch of that location WON'T be equal to the
  289. reg we stored from, and it's not worth trying to sort this out.
  290. *)
  291.  
  292.  
  293. OD    storedOD
  294.  
  295. objPtr whichRegs    class_is ODs_class
  296. objPtr stored_regs    class_is ODs_class
  297.  
  298. : RECORD_REG_STORE  { ^OD \ reg# -- }
  299.  
  300.     ^OD  copyOD: storedOD
  301.  
  302.     debug? if
  303.         ." recording store of " print: storedOD
  304.     then
  305.  
  306.     reg: opnd2  -> reg#            \ the reg we've stored
  307.     reg# select: whichRegs
  308.     CDP 4-  mark_use: whichRegs
  309.  
  310.     get: ivar> len in storedOD  4 <
  311.     IF    debug? if
  312.             ." no - len < 4 - not recording"
  313.         then
  314.         EXIT
  315.     THEN
  316.  
  317.     reg# select: stored_regs
  318.  
  319.     ^OD  copyOD: stored_regs
  320.  
  321.     get: ivar> opCDP        in whichRegs
  322.     put: ivar> lastRefCDP    in stored_regs
  323.  
  324.     CDP 4-  put: ivar> lastRefCDP in whichRegs
  325.     get: ivar> opType in whichRegs  otUnknown =
  326.     IF  otUnkStored  put: ivar> opType in whichRegs  THEN
  327.  
  328. (*
  329.     storedOD false  match?: whichRegs
  330.     IF    otUnknown  put: ivar> opType in whichRegs
  331.         noType       put: ivar> instrnType in whichRegs
  332.         addr: ivar> myRef in whichRegs  ->: tmpRef1
  333.         4 --> CDP
  334.         tmpRef1 reg_changed
  335.         4 ++> CDP
  336.         CDP 4-  put: ivar> validTillCDP in whichRegs
  337.         debug? if
  338.             ." invalidated earlier fetch of same location:"    print: whichRegs  cr
  339.         then
  340.     THEN
  341. *)
  342.  
  343.     reg# select: whichRegs
  344.     
  345.     debug? if
  346.         ." updated stored_regs:" cr printall: stored_regs cr
  347.     then
  348. ;
  349.  
  350.  
  351. : RECORD_GPR_STORE
  352.     GPRs -> whichRegs  stored_GPRs -> stored_regs
  353.     record_reg_store
  354. ;
  355.  
  356. : RECORD_FPR_STORE
  357.     FPRs -> whichRegs  stored_FPRs -> stored_regs
  358.     record_reg_store
  359. ;
  360.  
  361. (*
  362. : RECORD_FPR_STORE  { ^OD \ reg# -- }
  363.     FPR: opnd2  select: stored_FPRs
  364.     theOD copyWithCDP: stored_FPRs
  365.     get: ivar> opCDP        in FPRs
  366.     put: ivar> lastRefCDP    in stored_FPRs
  367. ;
  368. *)
  369.  
  370. : COMPILE_THE_STORE  { \ gpr# -- }
  371.     Agpr: theOD  -> gpr#
  372.  
  373.     refType: opnd2
  374.     CASE[    gprRef    ]=>        reg: opnd2 select: GPRs
  375.                             CDP put: ivar> lastRefCDP in GPRs
  376.                             
  377.         [    fprRef    ]=>        reg: opnd2 select: FPRs
  378.                             CDP put: ivar> lastRefCDP in FPRs
  379.  
  380.           DEFAULT=>            drop
  381.     ]CASE
  382.  
  383.     gpr# 13 16 within?
  384.     swap obj_base_reg = or
  385.     refType: ivar> B_opnd in theOD  litRef =  and
  386.  
  387.     NIF    
  388.         debug? if
  389.             ." it's a computed store" cr  print: theOD cr
  390.             ." current GPR " current: gprs . cr
  391.         then
  392.         free: opnd2        \ free the data reg - freeing it early is safe,
  393.                         \  and lets make_fetches_unknown mark the reg as
  394.                         \  "empty" so it can be reallocated
  395.  
  396.         make_fetches_unknown: GPRs
  397.         make_fetches_unknown: FPRs
  398.         invalidate_all: stored_GPRs
  399.         invalidate_all: stored_FPRs
  400.          compile: theOD
  401.         CDP -> backstop_CDP
  402.     ELSE
  403.  
  404.         theOD  invalidate_on_overlap: GPRs
  405.         theOD  invalidate_on_overlap: FPRs
  406.         theOD  invalidate_on_overlap: stored_GPRs
  407.         theOD  invalidate_on_overlap: stored_FPRs
  408.  
  409.         compile: theOD
  410.         free: opnd2        \ free the data reg
  411.  
  412. (*    Now we copy theOD to the corresponding stored_GPRs or stored_FPRs
  413.     location, and set the lastRefCDP ivar.  Note that this ivar has a
  414.     special meaning for stores - it's the CDP for where the stored reg's
  415.     value was generated.  The normal meaning wouldn't make sense for
  416.     stores anyway.
  417. *)
  418.         refType: opnd2
  419.         CASE[    gprRef    ]=>        theOD  record_GPR_store
  420.             [    fprRef    ]=>        theOD  record_FPR_store
  421.  
  422.               DEFAULT=>        to_be_written  drop
  423.         ]CASE
  424.  
  425. (*    Finally we set the fetch backstop to straight after the store, so that
  426.     we won't move any fetch forward past this point.  To be able to do this,
  427.     we'd need to do a full check for overlap possibilities, since any overlap
  428.     would invalidate moving the fetch forward.  This is doable, but rather
  429.     complicated, since we may have already invalidated the record of an
  430.     earlier store, so we'd need to keep a bytestring with info about all
  431.     stores in the current definition.  We could do this, but it's nasty, and
  432.     probably not worth it just for this situation, which will probably
  433.     hardly ever slow down a fetch anyway.
  434. *)
  435.         CDP -> fetch_backstop
  436.     THEN
  437. ;
  438.  
  439.  
  440. : DO_OP&STORE { len \ theOp -- }
  441.  
  442. (*    This handles an op into memory, such as ++> aValue.  We fetch, operate,
  443.     store.  On entry, the top of cstk is a reference to a reg with the target
  444.     addr.  The second cell is a ref to the reg we're operating into that target.
  445.     We start off with do_fetch which may cascade the address add.  Whatever it
  446.     does, it should leave the dest reg selected (where the data was fetched to).
  447.     This will designate the actual fetch operation done, and we can use
  448.     exactly this reg info to do the store later.  We ensure that any antecedent
  449.     regs aren't changed between the fetch and the store by bumping their refcnts
  450.     for the duration.
  451. *)
  452.     debug? if
  453.         ." do_op&store called" cr
  454.     then
  455.  
  456.     svOpcode -> theOp            \ gets clobbered
  457.     len 0 do_fetch                \ do the fetch - dest GPR left selected
  458.     gpr: cstk select: GPRs        \ but in case it wasn't, we ensure it is.
  459.                                 \ &&&& FPRs to_be_written !!!
  460.  
  461.     debug? if
  462.         ." fetch done, to GPR: " cr  print: GPRs
  463.     then
  464.  
  465.     addr: GPRs   copyOD: tmpOD            \ save target OD, since we'll store
  466.                                         \  using it shortly
  467.     allocate: ivar> A_opnd in tmpOD        \ Ensure any base regs needed for the
  468.     allocate: ivar> B_opnd in tmpOD        \  store, aren't clobbered by the op
  469.     otStore  put: ivar> opType in tmpOD
  470.     
  471. \ at this point the cstk is ( stk-opnd mem-opnd ). We now need
  472. \  to (in effect) postpone a SWAP, since if the op is subtract,
  473. \  the stk-opnd must be subtracted from the mem-opnd.
  474.  
  475.     swap_cstk
  476.     theOp -> operation  do_arith_op        \ do the operation
  477.     
  478.     1 operands                    \ get the result reg (will normally be different)
  479.     opnd1 ->: opnd2                \ compile_the_store expects it in opnd2
  480.     opnd1 ->: ivar> myRef in tmpOD
  481.                                 \ but the store of that reg will be to the location
  482.                                 \  we got before
  483.     debug? if
  484.         ." result reg:" gpr: opnd1  .g  cr
  485.     then
  486.  
  487.     tmpOD copyOD: theOD
  488.     
  489.     debug? if
  490.         ." theOD before store:" print: theOD cr
  491.     then
  492.     
  493.     compile_the_store
  494.         
  495.     debug? if  dasm  then
  496.  
  497.     free: ivar> A_opnd in tmpOD        \ Because we did allocate: on them above
  498.     free: ivar> B_opnd in tmpOD
  499. ;
  500.  
  501.  
  502. : (DO_STORE)        \ factors out common code from DO_STORE and DO_FP_STORE.
  503.  
  504.     opnd2 >myRef: theOD        \ the reg we're storing
  505.  
  506.     gpr: opnd1      >Agpr: theOD
  507.     0 >Blit: theOD
  508.     
  509.     debug? if
  510.         ." (do_store) called, with a straight store" cr
  511.         ." - initial store set up in theOD:" cr print: theOD cr
  512.         dasm
  513.     then
  514.  
  515.     cascade&match? drop        \ stores never match anything, but a cascade
  516.                             \  might get done
  517.     debug? if
  518.         ." after cascade&match?" cr print: theOD cr
  519.         ." opnd2 " print: opnd2 cr
  520.     then
  521.  
  522. \    opnd2 >myRef: theOD        \ the reg we're storing
  523.     debug? if
  524.         ." theOD set up for store:" cr print: theOD cr
  525.     then
  526.     compile_the_store
  527.  
  528.     free: opnd1            \ free the dest addr reg - if we cascaded, this will
  529.                         \  have been deleted, but then opnd1 will have been
  530.                         \  changed to noRef and the free: will be ignored.
  531. ;
  532.  
  533.  
  534. : DO_STORE  { len \ regForStore -- }
  535.  
  536.     debug? if
  537.         ." do_store called with opcode " svOpcode .h cr
  538.         printall: cstk  dasm
  539.     then
  540.  
  541. \    svOpcode dup otStore <>  swap otFPstore <>  and
  542.     svOpcode  $ FF and  otStore <>
  543.     IF    len do_op&store  EXIT  THEN
  544.  
  545. \ cascade&match? wants the address operand in opnd1, so we'll get
  546. \  them in reverse order:
  547.  
  548.     swap_cstk  2 operands    \ opnd2 = what we're storing, opnd1 = where
  549.     
  550.     refType: opnd2
  551.     SELECT[    gprRef    ]=>                \ nothing to do
  552.           [    litRef    ]=>        opnd2 get_to_reg? drop
  553.           
  554.           [    crRef    ]=>        opnd2  0  cr>this_gpr
  555.                               0 >gpr: opnd2
  556.  
  557.           DEFAULT=>            drop
  558.     ]SELECT
  559.  
  560. \ Now we have to check that the destination makes sense:
  561.  
  562.     refType: opnd1
  563.  
  564.     SELECT[    gprRef    ]=>                    \ nothing to do
  565.           [    litRef    ]=>            opnd1 get_to_gpr? drop
  566.           
  567.           [ gprNameRef    ]=>        opnd2 get_to_gpr? drop
  568.                                 gpr: opnd2  reg: opnd1  true  moveReg: GPRs
  569.                                 EXIT
  570.  
  571.           DEFAULT=>            214 die        \ impossible store destination!
  572.     ]SELECT
  573.  
  574. \ now we set things up in theOD, since we might be able to cascade the addr.
  575.  
  576.     clear: theOD
  577.     otStore        put: ivar> opType    in theOD
  578.     len            put: ivar> len        in theOD
  579.     
  580.     (do_store)
  581. ;
  582.  
  583.  
  584. : DO_FP_STORE  { len -- }
  585.  
  586.     debug? if
  587.         ." do_FP_store called with opcode " svOpcode .h cr
  588.         printall: cstk
  589.     then
  590.     
  591. \ cascade&match? wants the address operand in opnd1, so we'll
  592. \  organize things that way:
  593.  
  594.     1 foperands  opnd1 ->: opnd2        \ opnd2 = what we're storing
  595.     1 operands                            \ opnd1 = where
  596.     
  597.     ASSERT{ refType: opnd2  FPRref = }
  598.  
  599.     reftype: opnd1
  600.     SELECT[    gprRef    ]=>                \ normal store to mem - handled below
  601.  
  602.           [ fprNameRef    ]=>        fpr: opnd2  reg: opnd1  true  moveReg: FPRs
  603.                                 EXIT
  604.  
  605.           DEFAULT=>            214 die        \ impossible store destination!
  606.     ]SELECT
  607.  
  608. \ now we set things up in theOD, since we might be able to cascade the addr.
  609.  
  610.     clear: theOD
  611.     otFPStore    put: ivar> opType    in theOD
  612.     len            put: ivar> len        in theOD
  613.     
  614.     (do_store)
  615. ;
  616.  
  617.  
  618.  
  619. : SIZE>LEN                    \ converts our size codes to a length in bytes
  620.     SELECT[    0    ]=>        1
  621.           [    1    ]=>        2
  622.           [    2    ]=>        4
  623.           [    3    ]=>        8
  624.     DEFAULT=>
  625.     ]SELECT
  626. ;
  627.  
  628.  
  629. : @_H  { cfa \ flags size -- }
  630.     cfa ^extra_info -> cfa
  631.     cfa 1+ c@ -> size
  632.     cfa 3+ c@ -> flags
  633.     size size>len flags  do_fetch  ;
  634.  
  635.  
  636. : !_H  { cfa \ flags size -- }
  637.     cfa ^extra_info -> cfa
  638.     cfa    c@ -> svOpcode
  639.     cfa 1+ c@ -> size
  640.     size size>len  do_store  ;
  641.  
  642.  
  643. : F@_H  { cfa -- }    8  do_fp_fetch  ;
  644. : SF@_H  { cfa -- }    4  do_fp_fetch  ;
  645.  
  646. : F!_H  { cfa -- }  8  do_fp_store  ;
  647. : SF!_H { cfa -- }  4  do_fp_store  ;
  648.  
  649.  
  650. PPC? not
  651. [IF]
  652.  
  653. (*    Here in 68k mode we define some interim versions of some of our
  654.     floating point operations.  This allows us do some testing on the
  655.     FP code generation without having to load everything, and also lets
  656.     us target compile code in Setup to initialize the FP regs.
  657.     
  658.     As interim ops, these are immediate and can only be used in a
  659.     definition.
  660. *)
  661.  
  662. : F@    8  do_fp_fetch  ;    immediate
  663. : F!    8  do_fp_store  ;    immediate
  664.  
  665. : SF@    4  do_fp_fetch  ;    immediate
  666. : SF!    4  do_fp_store  ;    immediate
  667.  
  668. : F+    otFADD -> operation  dyadic_arith  ;        immediate
  669. : F-    otFSub -> operation  dyadic_arith  ;        immediate
  670. : F*    otFMUL -> operation  dyadic_arith  ;        immediate
  671. : FDROP    tmpRef1 fpop  free: tmpRef1  ;                immediate
  672. : FDUP    1 foperands  opnd1 fpush  opnd1 fpush
  673.         allocate: opnd1  ;                            immediate
  674.                             
  675. : FOVER    2 foperands  opnd1 fpush  opnd2 fpush  opnd1 fpush
  676.         allocate: opnd1  ;                            immediate
  677.  
  678. [ELSE]
  679.  
  680. (*    In PPC mode we define (vop) which is the basic word which compiles
  681.     a vector operation with 2 or 3 source operands and one destination.
  682.     As we don't have a vector stack, the vector operands must be able to be 
  683.     determined at compile time - i.e. they must be on cstk.
  684. *)
  685.  
  686. : (vop)  { opcode vecKind 4op? \ gpr# vr# storeback? op1? lit? litVal -- }
  687.  
  688.     false -> storeback?  false -> lit?  true -> op1?
  689.  
  690.     4op?
  691.     IF        4 operands
  692.     ELSE    3 operands
  693.             opnd3 ->: opnd4
  694.     THEN    
  695.     
  696. \ opnd1 = source1, opnd2 = source2, opnd3 = source3 if any, opnd4 = dest.
  697. \  Any of these operands will be vrNameRef if it's a vector register object.
  698.  
  699.     reftype: opnd4            \ dest
  700.     vrNameRef =
  701.     IF                        \ dest is a VR
  702.         reg: opnd4            \ dest
  703.         dup -> vr#
  704.         dup select: VRs  >Bvr: VRs
  705.     ELSE                    \ dest is in memory.  We don't have a vector
  706.                             \  stack, so we do the operation in vr0, then 
  707.                             \  store back.
  708.         true -> storeback?
  709.         opnd4 get_to_gpr? drop        \ make sure we have base addr in a gpr
  710.         0 -> vr#  0 select: VRs
  711.         otFetch otVecOffset +  put: ivar> opType in VRs
  712.         reg: opnd2  dup -> gpr#  >Agpr: VRs  0 >Blit: VRs
  713.         compile: VRs
  714.         0 >VR: opnd2
  715.     THEN
  716.  
  717. \ now we need to do some special things if we have a literal operand:
  718.  
  719.     opcode
  720.     CASE[ $ 80 ], [ $ 81 ]=>    \ vector splat/splat immediate.
  721.                                 \ For splat, opnd1 = source, opnd2 = literal indicating 
  722.                                 \ which element.
  723.                                 \ For splat immediate, opnd2 = literal being splatted, 
  724.                                 \ opnd1 is a dummy, since we always have to have 3 operands.
  725.  
  726.                 reftype: opnd2  litRef <>
  727.                 IF
  728.                     228 postpone literal  postpone die
  729.                                 \ "splat: or Nsplat: must have a literal operand"
  730.                     EXIT
  731.                 THEN
  732.                 lit: opnd2 -> litVal
  733.  
  734.                 opcode $ 81 =
  735.                 IF                \ splat immediate -- we need to check the literal is
  736.                                 \  within bounds.
  737.                     litVal -32 31 within? nip
  738.                     NIF 226 die  THEN        \ "Literal for Nsplat: must be between -32 and 31"
  739.                     vecKind $ 80 and
  740.                     NIF                        \ unsigned
  741.                         litVal 0< IF  227 die  THEN
  742.                             \ "Nsplat:  can't assign a negative literal to an unsigned vector"
  743.                     THEN
  744.                     false -> op1?        \ no operand 1 in this case
  745.                 THEN
  746.  
  747.                 true -> lit?
  748.  
  749.         DEFAULT=>  drop
  750.     ]CASE
  751.     
  752.     op1?
  753.     IF
  754.         reftype: opnd1  vrNameRef <>
  755.         IF            \ source is in mem.  We fetch it to vr1.
  756.             opnd1 get_to_gpr? drop
  757.             1 select: VRs
  758.             otFetch otVecOffset +  put: ivar> opType in VRs
  759.             reg: opnd1  >Agpr: VRs  0 >Blit: VRs
  760.             compile: VRs
  761.             free: opnd1
  762.             1 >VR: opnd1
  763.         THEN
  764.     ELSE
  765.         0 >vr: opnd1        \ no opnd1, so we just make sure the field is zero
  766.     THEN
  767.  
  768.     4op?
  769.     IF                    \ we need to check if operand 3 is in mem, and
  770.                         \  if so, fetch to vr2.
  771.         reftype: opnd3  vrNameRef <>
  772.         IF                \ it's in mem.
  773.             opnd3 get_to_gpr? drop
  774.             2 select: VRs
  775.             otFetch otVecOffset +  put: ivar> opType in VRs
  776.             reg: opnd3  >Agpr: VRs  0 >Blit: VRs
  777.             compile: VRs
  778.             free: opnd3
  779.             2 >VR: opnd3
  780.         THEN
  781.     THEN
  782.  
  783.     lit?
  784.     IF
  785.         vr# select: VRs
  786.         opcode  otVecOffset +  put: ivar> opType in VRs
  787.         vecKind  put: ivar> vecKind in VRs
  788.         reg: opnd1  >Avr: VRs            \ source register (zero if none)
  789.         litVal  >Blit: VRs                \ literal value
  790.         compile: VRs
  791.     ELSE
  792.         reftype: opnd2
  793.         vrNameRef <>
  794.         IF
  795.             opnd2 get_to_gpr? drop
  796.             2 select: VRs
  797.             otFetch otVecOffset +  put: ivar> opType in VRs
  798.             reg: opnd1  >Agpr: VRs  0 >Blit: VRs
  799.             compile: VRs
  800.             free: opnd2
  801.             2 >VR: opnd2
  802.         THEN
  803.  
  804.         vr# select: VRs
  805.         reg: opnd1  >Avr: VRs                \ first source operand
  806.         reg: opnd2  >Bvr: VRs                \ second source operand
  807.         4op?
  808.         IF    reg: opnd3  >Cvr: VRs  THEN        \ third source operand, if any
  809.  
  810.         opcode $ 200 or  put: ivar> opType in VRs
  811.  
  812.         opcode $ 23 $ 25 within? nip
  813.                     \ true if logical, for which vecKind is ignored.  
  814.                     \  In some situations we mightn't have passed in zero, 
  815.                     \  so in this case we just force it to zero.
  816.         not vecKind and
  817.         put: ivar> vecKind in VRs
  818.         compile: VRs
  819.     THEN
  820.  
  821.     storeback?
  822.     IF
  823.         gpr# >Agpr: VRs  0 >Blit: VRs
  824.         otStore otVecOffset +  put: ivar> opType in VRs
  825.         compile: VRs
  826.         gpr#  free_gpr
  827.     THEN
  828. ;
  829.  
  830. \ we define __v2op and __v3op in file Vectors since they need intrp1 
  831. \  which isn't defined till cg7.
  832.  
  833. [THEN]
  834.  
  835.  
  836. PPC?
  837. [IF]
  838. \ LITERAL is moved back to cg5 - we still need the old defn, and can't
  839. \  resort to ppc_immediate since in compiling numbers we need the new defn.
  840.  
  841. [ELSE]
  842.  
  843. : LITERAL    \ ( n -- )    Compiles a fetch of n as a literal.
  844.     \ We just push onto cstk, hoping we can combine with an
  845.     \  op at run time
  846.         clear: opnd1  >lit: opnd1
  847.         opnd1 push  ;                immediate
  848.  
  849. [THEN]
  850.  
  851. : fetchVal
  852.     64bit? IF 8 ELSE 4 THEN
  853.     0
  854.     do_fetch  ;
  855.     
  856.  
  857. : storeVal
  858.     64bit? IF 8 ELSE 4 THEN
  859.     do_store
  860. ;
  861.  
  862.  
  863. : VAL_H  { ^value -- }
  864.  
  865.     debug? if
  866.         ." val_h" cr
  867.     then
  868.  
  869.     ^value  2+ -> ^value    \ align on the reloc addr
  870.  
  871.     ^value @b&d                \ get final base reg# and displacement
  872.     (litAddr)                \ generates the addr in GPR given by res1 & pushes
  873.  
  874. \    gpr: res1  select: GPRs
  875. \    GPRs copyOD: valOD        \ save the OD in valOD as we may need it
  876.     svOpcode
  877.     NIF                        \ it's a fetch
  878.         fetchVal
  879.     ELSE                    \ it's some kind of store
  880.         storeVal
  881.     THEN
  882. ;
  883.  
  884. : FVAL_H  { ^value -- }
  885.     debug? if
  886.         ." fval_h" cr
  887.     then
  888.  
  889.     ^value  2+ -> ^value    \ align on the reloc addr
  890.  
  891.     ^value @b&d                \ get final base reg# and displacement
  892.     (litAddr)                \ generates the addr in GPR given by res1 & pushes
  893.  
  894.     svOpcode
  895.     NIF                        \ it's a fetch
  896.         8 do_fp_fetch
  897.     ELSE                    \ it's some kind of store
  898.         8 do_fp_store
  899.     THEN
  900. ;
  901.  
  902.  
  903. : CONST_H    \ ( cfa -- )
  904.     2+
  905.     @  postpone literal  ;        \ not too hard!
  906.  
  907. : FCON_H    \ ( cfa -- }
  908.     2+ #align8
  909.     lit_addr  postpone f@
  910. ;
  911.  
  912.  
  913. : FETCHREG    \ ( reg# code -- )
  914.     3 = IF
  915.         >gpr: opnd1     opnd1 push
  916.     ELSE
  917.         >fpr: opnd1  opnd1 fpush
  918.     THEN
  919.     allocate: opnd1  ;
  920.  
  921. (*
  922. : FETCHREG    \ ( reg# code -- )
  923.     3 = IF
  924.         localSect?
  925.         NIF
  926.             1st_gpr_local 2+  31 #P -  within?
  927.                             \ 2+ because we don't want to include I and the 
  928.                             \  do limit  reg in the test!
  929.             IF
  930.                 dup select: GPRs
  931.                 get: ivar> opType in GPRs  NIF  112 die  THEN
  932.             THEN
  933.         THEN
  934.         >gpr: opnd1     opnd1 push
  935.     ELSE
  936.         localSect?
  937.         NIF
  938.             1st_fpr_local  31 #FP -  within?
  939.             IF
  940.                 dup select: FPRs
  941.                 get: ivar> opType in FPRs  NIF  112 die  THEN
  942.             THEN
  943.         THEN
  944.         >fpr: opnd1  opnd1 fpush
  945.     THEN
  946.     allocate: opnd1  ;
  947. *)
  948.  
  949. : do_reg  { reg# code -- }
  950.     svOpcode
  951.     NIF                    \ this is a fetch
  952.         reg# code fetchReg
  953.     ELSE                \ this is some kind of store
  954.         svOpcode otStore =
  955.         NIF    reg# code fetchReg
  956.             svOpcode monadic?  NIF swap_cstk THEN
  957.             -> operation  do_arith_op
  958.         THEN
  959.         code 3 =
  960.         IF
  961.             1 operands
  962.             opnd1 get_to_gpr? drop
  963.             gpr: opnd1  reg#  true  moveReg: GPRs
  964.         ELSE
  965.             1 foperands
  966.             fpr: opnd1  reg#  true  moveReg: FPRs
  967.         THEN
  968.     THEN
  969. ;
  970.  
  971.  
  972. \ REG_H handles a reg reference - either GPR or FPR.  It's never
  973. \  called for a 68k register.
  974.  
  975. : REG_H  { cfa \ mode reg# -- }
  976.     cfa ^extra_info -> cfa
  977.     cfa 1+ c@        \ reg#
  978.     cfa c@            \ code - 3 = gpr, 4 = fpr
  979.     do_reg
  980. ;
  981.  
  982.  
  983. : LOC_H        \ note: loc# counts from right to left in the local/parm list,
  984.             \ but we're assigning regs from left to right in the list,
  985.             \ going from r31 down (since this simplifies EXECUTE).
  986.     drop
  987.     32  #PL loc# -  -  3  do_reg  ;
  988.  
  989. : FLOC_H    \ does the same job for floating parms/locals.
  990.     drop
  991.     32  #FPL loc# -  -  4  do_reg  ;
  992.  
  993.  
  994. : reg_name  ( regcode reg# -- )
  995.     clear: opnd1   >reg: opnd1
  996.     regcode>nameRef  >reftype: opnd1
  997.     opnd1 push
  998. ;
  999.  
  1000.  
  1001. : VECT_H  { ^vect -- }
  1002.  
  1003.     ^vect 2+ -> ^vect        \ align on the reloc addr
  1004.  
  1005.     ^vect @b&d                \ get final base reg# and displacement
  1006.     (litAddr)                \ generates the addr in GPR given by res1 & pushes
  1007.  
  1008.     svOpcode
  1009.     NIF                            \ it's an execute
  1010.         " doVect"  evaluate        \ late-bind using evaluate - doVect not defined yet
  1011.         true -> ctr_clobbered?    \ the vect might do anything!
  1012.  
  1013.     ELSE                        \ it's a store to the vect
  1014.         " reloc!"  evaluate
  1015.     THEN
  1016. ;
  1017.  
  1018.  
  1019. : SVECT_H  { ^vect -- }        \ system vectors are like vectors, but have a default
  1020.                             \ value 4 bytes after the regular one, which gets used
  1021.                             \ if the regular one is zero.
  1022.  
  1023.     ^vect 2+ -> ^vect        \ align on the reloc addr pointing to data area
  1024.  
  1025.     ^vect @b&d                \ get final base reg# and displacement
  1026.     (litAddr)                \ generates the addr in GPR given by res1 & pushes
  1027.  
  1028.     svOpcode
  1029.     NIF                            \ it's an execute
  1030.         " doSvect" evaluate        \ late-bind using evaluate - doSvec not defined yet
  1031.                                 \  the first time through
  1032.         true -> ctr_clobbered?    \ the vect might do anything!
  1033.     ELSE                        \ it's a store to the vect
  1034.         " reloc!"  evaluate
  1035.     THEN
  1036. ;
  1037.  
  1038. (*    Dynamic vectors are "lightweight" vectors in which we don't use a relocatable
  1039.     addr but just store the xt to be executed, which allows us to point into
  1040.     a module if we know it's safe.  These should never be saved in the dic and used
  1041.     after reloading - hence the name "dynamic".  Like system vectors, zero means
  1042.     use the default, but the default is always do nothing.
  1043. *)
  1044.  
  1045. : dynVect_h  { ^vect -- }
  1046.  
  1047.     ^vect 2+ -> ^vect        \ align on the reloc addr pointing to data area
  1048.  
  1049.     ^vect @b&d                \ get final base reg# and displacement
  1050.     (litAddr)                \ generates the addr in GPR given by res1 & pushes
  1051.  
  1052.     svOpcode
  1053.     NIF                            \ it's an execute
  1054.         " @ execute" evaluate
  1055.     ELSE                        \ it's a store to the vect
  1056.         4 do_store                \ store passed-in xt
  1057.     THEN
  1058. ;
  1059.  
  1060.  
  1061.  
  1062. : PM_H      \ ( cfa -- )
  1063.     ^extra_info
  1064.     w@  -> operation  do_arith_op
  1065. ;
  1066.  
  1067.  
  1068. : SHIFT_H    \ ( cfa -- )
  1069.     ^extra_info
  1070.     1+ c@  -> subOperation        \ 0 left, 1 logical right, 3 arith right
  1071.     otShift -> operation  dyadic_arith  ;
  1072.  
  1073.  
  1074. : MULTDIV_H        pm_h  ;
  1075.  
  1076. : CMP_H  { cfa \ 68kCode compWithZero? unsigned? -- }
  1077.     cfa ^extra_info -> cfa
  1078.     cfa 1+ c@  -> 68kCode
  1079.     68kCode $ 10 and -> compWithZero?
  1080.     68kCode $ F  and  comparison_codes + c@  -> subOperation
  1081.     subOperation 2 and  -> unsigned?
  1082.     compWithZero?
  1083.     IF        4 or> subOperation  unsigned? monadic_comparison
  1084.     ELSE    unsigned? dyadic_comparison
  1085.     THEN  ;
  1086.  
  1087.  
  1088. : FPCMP_H  { cfa \ code compWithZero? -- }
  1089.     cfa ^extra_info  -> cfa
  1090.     cfa 1+ c@  -> code
  1091.     code $ 4 and -> compWithZero?
  1092.     code         -> subOperation
  1093.     compWithZero?
  1094.     IF        FP_monadic_comparison
  1095.     ELSE    FP_dyadic_comparison
  1096.     THEN  ;
  1097.  
  1098.  
  1099. : pushDesc_h  { cfa \ hndlr -- }
  1100.     cfa ^extra_info -> cfa
  1101.     cfa c@            \ note the code is in the hi byte in case we ever need
  1102.                     \  a subtype in the lo byte.
  1103.  
  1104.     CASE[    otDUP    ]=>        \ If we're DUPing a CR ref, we're surely not going
  1105.                             \  to branch on it, but use it as an operand.  We get
  1106.                             \  much better code if we get it to a GPR straight
  1107.                             \  away.
  1108.                             postpone __>g
  1109.                             1 operands
  1110.                             opnd1 push  opnd1 push
  1111.                             allocate: opnd1
  1112.                             
  1113.         [    ot2DUP    ]=>        2 operands
  1114.                             opnd1 push opnd2 push
  1115.                             opnd1 push opnd2 push
  1116.                             allocate: opnd1  allocate: opnd2
  1117.  
  1118.         [    otDROP    ]=>        tmpRef1 pop  free: tmpRef1
  1119.         
  1120.         [    ot2DROP    ]=>        tmpRef1 pop  free: tmpRef1
  1121.                             tmpRef1 pop  free: tmpRef1
  1122.  
  1123.         [    otSWAP    ]=>        swap_cstk
  1124.                             
  1125.         [    otOVER    ]=>        2 operands
  1126.                             opnd1 push  opnd2 push  opnd1 push
  1127.                             allocate: opnd1
  1128.                             
  1129.         [    $ 68    ]=>        2 operands                                    \ NIP
  1130.                             free: opnd1
  1131.                             opnd2 push
  1132.  
  1133.         [    $ 69    ]=>        2 operands                                    \ TUCK
  1134.                             opnd2 push  opnd1 push  opnd2 push
  1135.         
  1136.         [    $ 6A    ]=>        rot_cstk                                    \ ROT
  1137.  
  1138.         [    $ 6B    ]=>        3 operands                                    \ DOWN
  1139.                             opnd3 push  opnd1 push  opnd2 push
  1140.                             
  1141.         [    $ 6C    ]=>        4 operands                                    \ 2SWAP
  1142.                             opnd3 push  opnd4 push  opnd1 push  opnd2 push
  1143.  
  1144.         [    $ 6D    ]=>        3 operands                                    \ 2PICK
  1145.                             opnd1 push  opnd2 push  opnd3 push  opnd1 push
  1146.                             allocate: opnd1
  1147.  
  1148.         [    $ 6E    ]=>        4 operands                                    \ 3PICK
  1149.                             opnd1 push  opnd2 push  opnd3 push  opnd4 push  opnd1 push
  1150.                             allocate: opnd1
  1151.  
  1152.         [    $ 6F    ]=>        4 operands                                    \ 3ROLL
  1153.                             opnd2 push  opnd3 push  opnd4 push  opnd1 push
  1154.  
  1155.         [    $ 72    ]=>        1 foperands                                    \ FDUP
  1156.                             opnd1 fpush  opnd1 fpush
  1157.                             allocate: opnd1
  1158.                             
  1159.         [    $ 73    ]=>        2 foperands                                    \ F2DUP
  1160.                             opnd1 fpush opnd2 fpush
  1161.                             opnd1 fpush opnd2 fpush
  1162.                             allocate: opnd1  allocate: opnd2
  1163.  
  1164.         [    $ 74    ]=>        tmpRef1 fpop  free: tmpRef1                    \ FDROP
  1165.         
  1166.         [    $ 75    ]=>        tmpRef1 fpop  free: tmpRef1                    \ F2DROP
  1167.                             tmpRef1 fpop  free: tmpRef1
  1168.  
  1169.         [    $ 76    ]=>        2 foperands
  1170.                             opnd2 fpush  opnd1 fpush                    \ FSWAP
  1171.  
  1172.         [    $ 77    ]=>        2 foperands                                    \ FOVER
  1173.                             opnd1 fpush  opnd2 fpush  opnd1 fpush
  1174.                             allocate: opnd1
  1175.                             
  1176.         [    $ 78    ]=>        2 foperands                                    \ FNIP
  1177.                             free: opnd1
  1178.                             opnd2 fpush
  1179.  
  1180.         [    $ 79    ]=>        2 foperands                                    \ FTUCK
  1181.                             opnd2 fpush  opnd1 fpush  opnd2 fpush
  1182.         
  1183.         [    $ 7A    ]=>        3 foperands
  1184.                             opnd2 fpush  opnd3 fpush  opnd1 fpush         \ FROT
  1185.  
  1186.         [    $ 7B    ]=>        3 foperands                                    \ FDOWN
  1187.                             opnd3 fpush  opnd1 fpush  opnd2 fpush
  1188.  
  1189.         [    $ 7C    ]=>        4 foperands                                    \ F2SWAP
  1190.                             opnd3 fpush  opnd4 fpush  opnd1 fpush  opnd2 fpush
  1191.  
  1192.  
  1193.     DEFAULT=>  drop
  1194.     ]CASE
  1195. ;
  1196.  
  1197.  
  1198. : SWAP_H    \ this is obsolete, but useful in testing before we've loaded
  1199.             \  the nuc.
  1200.     drop  swap_cstk  ;
  1201.  
  1202.  
  1203. : CompJSRlong    compile_call  ;
  1204.  
  1205.  
  1206. : INLINE_H  { cfa -- }
  1207.     true -> compinline?
  1208.     cfa 1+ count evaluate
  1209.     false -> compinline?  ;
  1210.  
  1211.  
  1212. : INLINE{  { \ str-addr --  }
  1213.     drop                            \ drop stack flag (ppc_entry will replace)
  1214.     DP                                \ Save DP
  1215.     curr-def 2- -> DP                \ back to flag bytes (will be replaced after
  1216.                                     \  the inline text)
  1217.     method?
  1218.     IF  $ BD40  ELSE  $ BD3C  THEN    \ replace handler code with appropriate
  1219.     DP 2- w!                        \  inline handler
  1220.     $ FF c,                            \ extra info mark, then the string (length in lo
  1221.     DP -> str-addr                    \  byte of extra info mark halfword).  Note this
  1222.     & }  ,str                        \  does "even" alignment at the end, but since
  1223.                                     \  it's starting from an odd byte, DP will be odd.
  1224.                                     \  We need to allow for the pad byte that might
  1225.                                     \  have been added, and allow for the 2 flag bytes.
  1226.                                     \ Thus, if the string length is even, the total
  1227.                                     \  len will be odd and there'll be a pad byte.  In
  1228.                                     \  this case we add 1 to DP, otherwise 2.
  1229.     str-addr c@ 1 and 1+ ++> DP
  1230.     align                            \ Then 4-byte align
  1231.     DP -> CDP
  1232.     -> DP                            \ restore DP
  1233.     0 -> state                        \ ppc_entry requires compilation off
  1234.     false ppc_entry                    \ recompile entry sequence
  1235.     method? IF drop 305 THEN        \ methods have different security marker
  1236.     str-addr count evaluate            \ compile out-of-line code
  1237.                                     \ note - this will be wound up properly when
  1238.                                     \  we hit the ; or ;m
  1239. ;
  1240. PPC? [IF] ppc_immediate [ELSE] immediate [THEN]
  1241.  
  1242.  
  1243.  
  1244. \    ================  MOVE and ALIGNED_MOVE  =================
  1245. (*
  1246. I'm still deciding what's the best way to handle these.  I think that
  1247. for an aligned move of more than a couple of cells, it's OK to compile
  1248. a branch-on-count loop, since branch prefetch will get rid of any branch
  1249. latency, and there'll be no pipeline stall since the branch will only
  1250. depend on the count register.
  1251.  
  1252. For move_h, the moves could overlap, so for now I'll just do a call to
  1253. the compiled definition for MOVE, which will just call BlockMoveData.  Later
  1254. I could check the operands and use alignedMove if I can detect at compile
  1255. time that the move is aligned and non-overlapped.
  1256.  
  1257. *)
  1258.  
  1259. : Move_h        call_h  ;
  1260.  
  1261. (*    For alignedMove, we can assume the starting addresses are aligned, and
  1262.     there's no overlap.  If the move is short enough, I'll just compile
  1263.     some inline load and store instructions.  Otherwise I'll call the
  1264.     compiled defn for ALIGNED_MOVE, which will use a loop or a call to
  1265.     BlockMoveData.
  1266. *)
  1267.  
  1268. : AlignedMove_h  { \ len cnt offs remainder -- }
  1269.     1 operands
  1270.     refType: opnd1  litRef =
  1271.     IF    lit: opnd1  -> len
  1272.         len 20 <=
  1273.         IF    drop        \ we'll generate inline instructions.  We 
  1274.                         \  don't need the cfa of aligned_move
  1275.             len 2 >> -> cnt
  1276.             len 3 and -> remainder
  1277.             0 -> offs
  1278.             cnt FOR
  1279.                 postpone over  offs postpone literal  postpone +
  1280.                 postpone @
  1281.                 postpone over  offs postpone literal  postpone +
  1282.                 postpone !
  1283.                 4 ++> offs
  1284.             NEXT
  1285.             remainder FOR
  1286.                 postpone over  offs postpone literal  postpone +
  1287.                 postpone c@
  1288.                 postpone over  offs postpone literal  postpone +
  1289.                 postpone c!
  1290.                 1 ++> offs
  1291.             NEXT
  1292.             postpone 2drop   EXIT
  1293.         THEN
  1294.     THEN
  1295.     opnd1 push  call_h
  1296. ;
  1297.  
  1298.  
  1299.  
  1300. \    ================== MODULE SUPPORT ====================
  1301.  
  1302. PPC?
  1303. [IF]
  1304.  
  1305. (*
  1306. Here's the format of an imported word:
  1307.     n bytes        header
  1308.     2 bytes        handler code $BD2E
  1309.     2 bytes        export table offset for this word
  1310.     4 bytes        reloc addr of module object
  1311.  
  1312. We come here to imported_h when a call to an imported word has
  1313. to be compiled.  We compile a push of the xt of the word, then a
  1314. call to enterMod, which does the main work.  We put enterMod in
  1315. zModules, since it has to do a late-bound call to the module
  1316. object, and this is much easier if it's not in the target
  1317. compilation, and is also easier to debug.
  1318. *)
  1319.  
  1320. : IMPORTED_H  ( xt -- )
  1321.     lit_addr                    \ compile push of xt, for enterMod
  1322.     ['] enterMod  call_h        \ then compile call to enterMod
  1323.                                 \  which does the call to the module
  1324. ;
  1325.  
  1326. [THEN]
  1327.  
  1328.  
  1329. \    ================== UTILITY PPC ROUTINES ====================
  1330.  
  1331. PPC? not
  1332. [IF]
  1333.  
  1334. : (REG)    \ ( reg# code -- )  defining word defining a register.
  1335.     ppc_header
  1336.     $ BD0A codeW,        \ handler code for reg_h
  1337.     $ FF02  codeW,        \ extra info mark, 2 bytes extra info
  1338.     ( code ) codeC,
  1339.     ( reg# ) codeC,
  1340.     0 codeW,            \ align
  1341. ;
  1342.  
  1343. : GPR  ( reg# -- )  3 (reg)  ;    \ 3 = gpr -- we used it for D reg on 68k
  1344. : FPR  ( reg# -- )    4 (reg)  ;    \ 4 = fpr
  1345.  
  1346. [THEN]
  1347.  
  1348. mainData_reg    gpr  MAINDATA
  1349. modData_reg        gpr  MODDATA
  1350. mainCode_reg    gpr  MAINCODE
  1351. modCode_reg        gpr  MODCODE
  1352. SP_reg            gpr  SP
  1353. RP_reg            gpr  RP
  1354. FSP_reg            gpr  FSP
  1355. obj_base_reg    gpr  (^BASE)
  1356. \ I_reg            gpr  I    - moved to pnuc1 since we still need orig defn
  1357. do_limit_reg    gpr  do_limit
  1358. RTOC_reg        gpr  RTOC
  1359. 1                gpr  sys_SP
  1360. 0                gpr  GPR0
  1361. rX_reg            gpr  rX
  1362. rY_reg            gpr  rY
  1363. 31                gpr  LOCREG            \ for temp objects - gets patched to
  1364.                                     \  the appropriate reg# by temp{
  1365.  
  1366. 31                gpr  ^constData        \ points to constant data for curr
  1367.                                     \  defn - patched to approp reg#
  1368.                                     \  by set_constData_reg
  1369.                                 
  1370.                                 
  1371.                         
  1372.  
  1373. 14                fpr  0.0        \ we always have zero in fpr14
  1374.  
  1375.  
  1376. \ IMPORTANT NOTE:  Since we sometimes save and restore FPRs onto the
  1377. \  return stack, we always keep RP 8-byte aligned.  So >R and R< 
  1378. \  use an 8 byte increment/decrement, not 4.  We provide >Rx and
  1379. \  R>x for internal use only, which don't 8-byte align, for setting
  1380. \  up things like DO loops where we can be sure we'll end up 8-byte
  1381. \  aligned anyway.
  1382.  
  1383. : (>R)  { 8align? -- }
  1384.     1 operands
  1385.     opnd1 RP_reg 
  1386.     8align? if -8 else 1cell negate then  true  push_to_mem
  1387.     ( false -> leaf? )
  1388. ;
  1389.  
  1390. (*    The idea of the "false -> leaf?" was, that if we're in a leaf
  1391.     proc, the return addr isn't on the return stack, and this might
  1392.     break some code that tries to access the rtn addr with rtn stack
  1393.     operations.  But this sort of monkeying with the rtn addr is highly
  1394.     nonstandard, and would never work anyway if there are locals, so
  1395.     we're not going to support it.
  1396. *)
  1397.  
  1398.     
  1399. : (R>)    { 8align? -- }
  1400.     getFreeReg: GPRs  >gpr: res1
  1401.     RP_reg 0
  1402.     8align? if 8 else 1cell then  compPull: GPRs
  1403.     res1 push
  1404.     ( false -> leaf? )  ;
  1405.  
  1406. \ >R, R> and R@ are in cg-cond.
  1407.  
  1408. forward marker_h
  1409.  
  1410. : NIMPL
  1411.     ." selector not implemented: "
  1412.     hex svSelector .  ."   opcode: " svOpcode . cr
  1413.     decimal
  1414.     1 die
  1415. ;
  1416.  
  1417. ppc?
  1418. [IF]
  1419.  
  1420. : does_h  { xt -- }
  1421.     xt 2+ @abs        \ addr of data area of CREATEd word
  1422.     lit_addr        \ compile a push of that addr for the runtime
  1423.                     \  (does) code
  1424.     xt 6 + @abs        \ xt of the runtime code
  1425.     call_h
  1426. ;
  1427.  
  1428. [ELSE]
  1429.  
  1430. : does_h    nimpl  ;
  1431.  
  1432. [THEN]
  1433.  
  1434.  
  1435. : compPlLoop    nimpl  ;
  1436. : hDoEx            nimpl  ;
  1437. : hcompimp        nimpl  ;
  1438. : bit_h            nimpl  ;
  1439. : hLoadBA        nimpl  ;
  1440. : FixDoes        nimpl  ;
  1441. : hPatch        nimpl  ;
  1442. \ : Floc_h        nimpl  ;
  1443. \ : Fcon_h        nimpl  ;
  1444. \ : Fval_h        nimpl  ;
  1445. : FP1_h            nimpl  ;
  1446. : FP2_h            nimpl  ;
  1447. : hcompFPUL        nimpl  ;
  1448. : FCRcon_h        nimpl  ;
  1449. : hColA            nimpl  ;
  1450. : hDefnEnd        nimpl  ;
  1451. : colNoOpt_h    nimpl  ;
  1452. : hComputedJMP    nimpl  ;
  1453. : hEB            nimpl  ;
  1454.  
  1455. ppc? not [if]
  1456. : imported_h        nimpl  ;
  1457. : class_in_mod_h    nimpl  ;
  1458. [then]
  1459.  
  1460.  
  1461. (*
  1462. PPC_compile is the main word which gets called from the Mops system to
  1463. compile PPC code.  We do this by setting PPC? true, and setting the
  1464. vector PPCvec to point to PPC_compile.
  1465. This calls PPC_interpret if STATE is zero.
  1466. On the PPC we need it to be a forward defn, hence what follows...
  1467. *)
  1468.  
  1469. PPC? not
  1470. [IF]
  1471.   forward  PPC_compile
  1472. [THEN]
  1473.  
  1474.  
  1475. \ ppc? [if] +echox [then]
  1476.  
  1477. : PPC_interpret  ( maybe xt here ) { handler opcode \ hndlr_code -- }
  1478.  
  1479.     handler    $ FF00 and  -> hndlr_code
  1480.  
  1481. [ ppc? not ]
  1482. [if]
  1483.     hndlr_code $ BE00 =
  1484.     IF  ." can't execute a PPC colon defn on 68k!" 1 die  THEN
  1485. [then]
  1486.  
  1487. \    hndlr_code $ BC00 <>
  1488. \    IF  ." can't execute this PPC word on 68k!"  1 die  THEN
  1489.     
  1490.     handler  $ FF and
  1491. [ PPC? [IF] hexx [ELSE] hex [THEN] ]
  1492.     SELECT[    1    ]=>        \ maybe it's OK to execute a 68k word?  Let's see...
  1493.                     $ deadbeef $ 103 2drop  execute
  1494.  
  1495.           [    2    ]=>        2+ @                \ const_h
  1496.           [    3    ]=>        2+ @abs @            \ val_h
  1497.           [    4    ]=>        2+ @abs                \ create_h
  1498.  
  1499.           [    8    ]=>        $ deadbeef $ 104 db ppc? drop 2drop  !        \ store_h 
  1500.           [    B    ]=>        2+ @abs                \ obj_h
  1501.           [    1D    ]=>        ppc_obj                \ class name - i.e. create
  1502.                                               \  an object of that class
  1503.           [    38    ]=>                            \ hNoOpt is a no-op on PPC
  1504.           [    3C    ]=>        inline_h            \ inlines are sometimes
  1505.                                               \  OK in interpret mode
  1506.           [    41    ]=>        marker_h
  1507.  
  1508.          DEFAULT=>        ." illegal selector for PPC_interpret: " .h cr
  1509.     ]SELECT
  1510. [ PPC? [IF] decimalx [ELSE] decimal [THEN] ]
  1511. ;
  1512.  
  1513.  
  1514. :f PPC_compile  ( maybe xt here ) { handler opcode \ hndlr_code -- }
  1515.  
  1516.     PPC? NIF ." whooops" 1 die  THEN
  1517.  
  1518.     0 -> operation  0 -> subOperation
  1519.     opcode -> svOpcode  0 -> svSelector
  1520.  
  1521.     handler    $ FF00 and  -> hndlr_code
  1522.  
  1523.     hndlr_code $ FF00 =
  1524.     IF        \ it's a 68k-style handler code - convert to PPC equivalent
  1525.         handler negate 2/  -> handler
  1526.     THEN
  1527.  
  1528. [ ppc? not ]
  1529. [IF]
  1530.     state NIF  handler opcode  PPC_interpret  EXIT  THEN
  1531. [THEN]
  1532.  
  1533.     hndlr_code $ BE00 =
  1534.     IF  call_h  EXIT  THEN          \ normal PPC call
  1535.  
  1536.     handler    $ FFFF and  $ BF01 =
  1537.     IF  call_extern  EXIT  THEN      \ external call (SYSCALL or EXTERN)
  1538.  
  1539.     handler  $ FF and  -> svSelector
  1540.  
  1541.     [ debug? ] [if]
  1542.         ." selector " svSelector .h  ."  opcode " svOpcode .h  cr
  1543.     [then]
  1544.     
  1545. [ PPC? [IF] hexx [ELSE] hex [THEN] ]
  1546.     svSelector
  1547.     SELECT[    1    ]=>        cr ." can't compile a call to a 68k word from PPC code!"
  1548.                         1 die
  1549.  
  1550.           [    2    ]=>        const_h
  1551.           [    3    ]=>        val_h
  1552.           [    4    ]=>        create_h
  1553.           [    5    ]=>        vect_h
  1554.           [    6    ]=>        pm_h
  1555.           [    7    ]=>        @_h
  1556.           [    8    ]=>        !_h
  1557.           [    9    ]=>        callStr_h
  1558.           [    A    ]=>        reg_h
  1559.           [    B    ]=>        obj_h
  1560.           [    C    ]=>        does_h
  1561.           [    D    ]=>        loc_h
  1562.           [    E    ]=>        litAddr_h
  1563.           [    F    ]=>        pushDesc_h
  1564.           [    10    ]=>        cmp_h
  1565.           [    11    ]=>        postpone literal    \ "hLiteral" on 68k is same as literal
  1566.           [    12    ]=>        CompExit
  1567.           [    13    ]=>        CompJSRlong
  1568.           [    14    ]=>        pif
  1569.           [    15    ]=>        compPlLoop
  1570.           [    16    ]=>            \ hmentry does nothing - we handle at compile_prolog
  1571.           [    17    ]=>        [ ppc? ] [if] dbgr [else] PLentry [then]
  1572.                               \ this handler code isn't used in PPC code - PLentry is
  1573.                               \  called directly from { etc.
  1574.           [    18    ]=>        heb
  1575.           [    19    ]=>        \ hStkObj    - never called from here?
  1576.                               to_be_written
  1577.           [    1A    ]=>        hDoEx
  1578.           [    1B    ]=>        genaddr
  1579.           [    1C    ]=>        genxaddr
  1580.           [    1D    ]=>        class_h        \ note - won't get called on 68k - ppc_obj
  1581.                                       \  is what gets called
  1582.           [    1E    ]=>        hcompimp
  1583.           [    1F    ]=>        val_h        \ objPtr_h - fetches are identical to values
  1584.           [    20    ]=>        bit_h
  1585.           [    21    ]=>        swap_h
  1586.           [    22    ]=>        hLoadBA
  1587.           [    23    ]=>        FixDoes
  1588.           [    24    ]=>        hPatch
  1589.           [    25    ]=>        Floc_h
  1590.           [    26    ]=>        Fcon_h
  1591.           [    27    ]=>        Fval_h
  1592. \          [    28    ]=>        FP1_h
  1593. \          [    29    ]=>        FP2_h
  1594.           [    2A    ]=>        FPcmp_h
  1595.           [    2B    ]=>        hcompFPUL
  1596.           [    2C    ]=>        FCRcon_h
  1597.           [    2D    ]=>        class_h        \ actually class_in_mod_h, but they're
  1598.                                       \  exactly the same!
  1599.           [    2E    ]=>        imported_h
  1600.           [    2F    ]=>        hColA
  1601.           [    30    ]=>        shift_h
  1602.           [    31    ]=>        hDefnEnd
  1603.           [    32    ]=>        F@_h
  1604.           [    33    ]=>        F!_h
  1605.           [    34    ]=>        builds_h
  1606.           [    35    ]=>        MultDiv_h
  1607.           [    36    ]=>        Move_h
  1608.           [    37    ]=>        AlignedMove_h
  1609.           [    38    ]=>            \ hNoOpt is a no-op on the PPC
  1610.           [    39    ]=>        colNoOpt_h
  1611.           [    3A    ]=>        hComputedJMP
  1612.           [    3B    ]=>        dynVect_h
  1613.           [    3C    ]=>        inline_h            \ won't be used for  as on 68k
  1614.           [    3D    ]=>        sVect_h                \ won't be used for RBsysCall ditto
  1615.  
  1616. \ these following ones aren't defined or used on the 68k:
  1617.  
  1618. \          [    3E    ]=>        >r_h
  1619. \          [    3F    ]=>        r>_h
  1620.           [    40    ]=>        inline_h            \ inline methods
  1621.           [    41    ]=>        marker_h
  1622.           [    42    ]=>        SF@_h
  1623.           [    43    ]=>        SF!_h
  1624.           
  1625.          DEFAULT=>        ." illegal selector: $" .h  cr 1 die
  1626.          [ ppc? ] [if] dbgr [then]
  1627.     ]SELECT
  1628. [ PPC? [IF] decimalx [ELSE] decimal [THEN] ]
  1629. ;f
  1630.  
  1631.  
  1632. (*                ============================
  1633.  
  1634.     ?trap is just for the code generator.  It converts a preceding comparison
  1635.     to a trap instruction, for 1-instruction bounds checking.  We trap if
  1636.     the comparison result was true.
  1637.  
  1638.                   ============================
  1639. *)
  1640.  
  1641. : ?TRAP  { \ TO_bit# unsigned? -- }
  1642.     1 operands
  1643.     [ debug? ] [if]
  1644.         ." ?trap - opnd1:" cr  print: opnd1
  1645.     [then]
  1646.     refType: opnd1
  1647.     litRef =
  1648.     IF                \ operands to comparison were known at compile time, so
  1649.                     \  we can do the check straight away:
  1650.         lit: opnd1  0EXIT
  1651.         ." range check error found at compile time"  1 die
  1652.     THEN
  1653.  
  1654.     CR: opnd1  select: CRs
  1655.  
  1656. \ we work out the TO-field bits to set, based on the condition in
  1657. \  opnd1 and whether the comparison was signed or unsigned.  The 3
  1658. \  leftmost bits are the same as CR field bits, but then there are
  1659. \  2 more bits for u< and u>.
  1660.  
  1661.     get: ivar> bit# in opnd1  -> TO_bit#
  1662.     get: ivar> opType in CRs  otUCMP =  -> unsigned?
  1663.     unsigned?  IF  3 ++> TO_bit#  THEN
  1664.     $ 10 TO_bit# >>
  1665.     unsigned?
  1666.     IF        get: ivar> 1_is_true? in opnd1  NIF  $ 07    xor  THEN
  1667.     ELSE    get: ivar> 1_is_true? in opnd1    NIF  $ 1C    xor  THEN
  1668.     THEN
  1669.     put: ivar> subType in CRs
  1670.     otTrap put: ivar> opType in CRs
  1671.     recompile: CRs
  1672.     clear: CRs            \ not a CR op any more
  1673. ;
  1674. PPC? [IF]  ppc_immediate  [ELSE]  immediate  [THEN]
  1675.  
  1676. (*                ============================
  1677.  
  1678.    Here we define some ops as immediate macros using eval" - these were primitives
  1679.    in the 68k version, but our PPC code generator will produce optimum code from
  1680.    the macros - much better than calling out-of-line code.
  1681.  
  1682.                   ============================
  1683. *)
  1684.  
  1685. PPC? 
  1686. [IF]
  1687.  
  1688. : ?DUP    inline{ dup if dup then}  ;
  1689. : 0DUP    inline{ dup nif dup then} ;
  1690.  
  1691. [ELSE]
  1692.  
  1693. : ?DUP    eval" dup if dup then"  ;    immediate
  1694. : 0DUP    eval" dup nif dup then"  ;    immediate
  1695.  
  1696. [THEN]
  1697.  
  1698. (*                    ============================
  1699.  
  1700.    Here we define any defining words we need to build special kinds of
  1701.    headers on the PPC.
  1702.    
  1703.    Generally these headers contain a handler code and extra info bytes which just
  1704.    give instructions to the code generator, and whose meaning is implied by the
  1705.    particular handler code.  These bytes are headed by ah "extra info mark" - since
  1706.    this comes in the same position as the flag bytes on a normal colon defn, we'll
  1707.    use a value which is impossible for the flag bytes, just to prevent confusion.
  1708.    We'll use FFxx, where xx is the number of extra info bytes (excluding the mark).
  1709.    
  1710.    Then if normal out-of-line code follows (which can be called by EXECUTE), it
  1711.    will follow the extra info bytes.  We'll pad to an odd-halfword boundary, then
  1712.    put the normal flag bytes, then the code.
  1713.  
  1714.                       ============================
  1715. *)
  1716.  
  1717. \ Use special_op thus:
  1718.  
  1719. \ $ BD06 otAdd  special_op +  ;
  1720.  
  1721. \ The handler code and the extra info code is pushed before special_op, then
  1722. \ the name follows.
  1723.  
  1724.  
  1725. : special_op  { hndlr code \ cfa --  }
  1726.     ppc_header
  1727.     hndlr codeW,        \ pm_h code
  1728.     CDP -> cfa
  1729.     $ FF02 codeW,        \ extra info mark, 2 bytes extra info
  1730.     code codeW,            \ the info
  1731.     0 codeW,            \ initial flag bytes for out-of-line code
  1732.                         \  (we should now be aligned)
  1733.     false -> method?
  1734.     false ppc_entry        \ compile entry for OUL code
  1735.     cfa hndlr code  ppc_compile            \ compile  OUL code
  1736.     
  1737.     [ ppc? ] [if]
  1738.         curr-def 2- (;)  300 ?defn        \ wind up OUL code - this is
  1739.                                         \  the same as "postpone ;" but
  1740.                                         \  we can't do that here!
  1741.     [else]
  1742.         postpone ;
  1743.     [then]
  1744. ;
  1745.  
  1746.  
  1747. PPC? not
  1748. [IF]
  1749.  
  1750. : dummy_op  { hndlr -- }    \ currently this is just used to define locParm and
  1751.                             \  FlocParm, which don't do anything in themselves
  1752.                             \  except have handler codes which cause locals to be
  1753.                             \  accessed.
  1754.     ppc_header
  1755.     hndlr codeW,
  1756.     0 codeW,        \ align
  1757. ;
  1758.  
  1759. [THEN]
  1760.  
  1761.  
  1762. : fetch_op  { code flags \ cfa -- }
  1763.     ppc_header
  1764.     $ BD07 codeW,        \ @_h code
  1765.     CDP -> cfa
  1766.     $ FF04 codeW,        \ extra info mark, 4 bytes extra info
  1767.     code codeW,  flags codeW,
  1768.     0 codeW,            \ padding to get to odd halfword
  1769.     0 codeW,            \ initial flag bytes for out-of-line code
  1770.                         \  (we should now be aligned)
  1771.     false ppc_entry
  1772.     cfa  $ BD07  code  ppc_compile
  1773.  
  1774.     [ ppc? ] [if]
  1775.         curr-def 2- (;)  300 ?defn        \ wind up OUL code
  1776.     [else]
  1777.         postpone ;
  1778.     [then]
  1779. ;
  1780.  
  1781.  
  1782. : simple_op  { hndlr \ cfa -- }
  1783.     ppc_header
  1784.     hndlr codeW,        \ handler code
  1785.     CDP -> cfa
  1786.     0 codeW,            \ initial flag bytes for out-of-line code
  1787.                         \  (we should now be aligned)
  1788.     false -> method?
  1789.     false ppc_entry        \ compile entry for OUL code
  1790.     cfa hndlr 0  ppc_compile            \ compile  OUL code
  1791.  
  1792.     [ ppc? ] [if]
  1793.         curr-def 2- (;)  300 ?defn        \ wind up OUL code
  1794.     [else]
  1795.         postpone ;
  1796.     [then]
  1797. ;
  1798.  
  1799.  
  1800. PPC?
  1801. [IF]
  1802.   endload
  1803. [THEN]
  1804.  
  1805.  
  1806. 0    value    cg_CDP
  1807. 0    value    cg_DP
  1808. 0    value    norm_CDP
  1809. 0    value    norm_DP
  1810.  
  1811. : CG_CODE_START
  1812.     CDP -> norm_CDP    cg_CDP -> CDP
  1813.     cr
  1814.     ." code gen code start: $" CDP .h cr
  1815. ;
  1816.  
  1817. : CG_CODE_END
  1818.     cr cr
  1819.     ." code gen code end:  $"  CDP .h cr
  1820.     ." code gen code size: $"  CDP  cg_CDP - .h cr
  1821.     CDP nuc_code_start  u> IF ." cg code overran its area!" QUIT  THEN
  1822.     norm_CDP -> CDP
  1823. ;
  1824.  
  1825.  
  1826. : CG_DATA_START
  1827.     DP  -> norm_DP    cg_DP  -> DP
  1828.     ." code gen data start: $"  DP .h cr
  1829. ;
  1830.  
  1831. : CG_DATA_END
  1832.     cr cr
  1833.     ." code gen data end:  $"   DP .h cr
  1834.     ." code gen data size: $"    DP  cg_DP  - .h cr
  1835.     DP  nuc_data_start  u> IF ." cg data overran its area!" QUIT  THEN
  1836.     norm_DP -> DP
  1837. ;
  1838.  
  1839.  
  1840.  
  1841. : CROSS        \ crosses the fence into PPC-land - starts PPC compilation.
  1842.  
  1843. cr cr ." *************** PPC compilation started ***************" cr
  1844.  
  1845.     ['] PPC_compile  -> PPCvec
  1846.     true -> PPC?                    \ PPC compilation on
  1847.     true -> crossed?
  1848.  
  1849. \ Note: words such as CODE, which use a separate CDP, won't
  1850. \  work as expected until PPC? is set true, since before then
  1851. \  we keep it tied to DP so common code can be used.
  1852.  
  1853.     0 -> #P  0 -> #PL
  1854.     align4                    \ 4-byte align in data area
  1855.     DP -> data_start
  1856.     $ A000  reserve            \ put code up the dictionary, clear data area
  1857.  
  1858. \ now we set up the initial CDP, DP, code_start, code_limit, data_start
  1859. \  and data_limit
  1860.  
  1861.     DP
  1862.     dup  -> CDP  dup -> data_limit  dup -> code_start
  1863.     room +  -> code_limit
  1864.  
  1865.     $ 48000000 code,            \ put a branch at the start of the code, which
  1866.                                 \  will be resolved by INITIAL_ENTRY_POINT
  1867.                                 \  to our real initial entry point.
  1868.  
  1869.     info_block_size code_reserve    \ and then reserve space for the info block
  1870.                                     \  which follows.  This gets set up when we
  1871.                                     \  write the PEF
  1872.  
  1873.     0 -> 1st_defn                \ no defn yet
  1874.     data_start -> DP
  1875.  
  1876.     TOC_size  allot                \ initially allot TOC entries at start of data
  1877.  
  1878. \ now for the target compilation, we want the code generator to come
  1879. \  below the nucleus so we can omit it in installed apps.  So we now
  1880. \  allocate space for it in the code and data areas:
  1881.  
  1882.     CDP -> cg_CDP                \ the start of the cg's code area
  1883.     DP -> cg_DP
  1884.     $ 22A00 code_reserve        \ currently we need about 220xx
  1885.     $ 8000 reserve                \ currently we need about 71xx
  1886.     
  1887. \ now we're where we want the nuc to start
  1888.     CDP -> nuc_code_start
  1889.     DP  -> nuc_data_start
  1890. \ data_start -> nuc_data_start  4 ++> nuc_data_start
  1891.  
  1892.  
  1893. ." code_start     "    code_start        .h cr
  1894. ." data_start     "    data_start        .h cr
  1895. ." nuc_code_start "    nuc_code_start    .h cr
  1896. ." nuc_data_start "    nuc_data_start    .h cr
  1897. ." mainCode       "    mainCode_val    .h cr
  1898. ." mainData       "    mainData_val    .h cr cr
  1899.  
  1900.     CDP $ D000 erase        \ clear code area which makes it easier to see what we generated
  1901.  
  1902.     gpr_call_cnt setup_cstk
  1903.     fpr_call_cnt setup_fcstk
  1904.     new: eq_ranges  new: const_data  new: sv_const_data
  1905. ;
  1906.  
  1907.  
  1908. : .STK        printall: cstk  ;
  1909. : .STK2        printall: cstk2  ;
  1910.  
  1911. : ENDPPC
  1912.     0 -> PPCvec
  1913.     true -> 68k?
  1914.     PPC? 0EXIT                    \ out if windup already done
  1915.     false -> PPC?
  1916.     CDP    -> code_limit
  1917.     DP    -> data_limit
  1918.     CDP -> DP                    \ put DP back to normal place
  1919. ;
  1920.  
  1921.  
  1922. : INITIAL_ENTRY_POINT
  1923.     CDP -> init_entry  ;        immediate
  1924.  
  1925. : .SIZE        ." code size: "  CDP 1st_defn -  . cr
  1926.             ." data size: "  DP data_start - . cr  ;
  1927.  
  1928.  
  1929. :f DASM        1st_defn CDP 2dup  set_disasm_call_range
  1930.             disasm_rng  cr
  1931. ;f
  1932.  
  1933. :f DCURR        curr-def-code CDP  set_disasm_call_range
  1934.             CDP dup 96 -  swap  disasm_rng  cr
  1935. ;f
  1936.  
  1937.  
  1938. : ZZ
  1939.     endPPC
  1940.     release: const_data
  1941.     gpr_call_cnt setup_cstk  ;
  1942.  
  1943. :f Z
  1944. \    endPPC
  1945.     .stk  dasm cr .size  ;f
  1946.  
  1947. : ZB  { #back -- }
  1948. \        endPPC
  1949.         .stk
  1950.         code_start CDP  set_disasm_call_range
  1951.         CDP dup  #back - swap  disasm_rng
  1952.         cr .size  ;
  1953.  
  1954. :f ZS    $ 200  zb  ;f
  1955. : ZL    $ 800  zb  ;
  1956.  
  1957. : DW    disasm_word  ;
  1958.  
  1959. : DF    \ "disassemble from"
  1960.     endPPC  .stk
  1961.     '  >link  CDP  dup set_disasm_call_range  disasm_rng
  1962.     cr  .size  ;
  1963.     
  1964.  
  1965. : RL    zz  rl  ;
  1966. : FM    zz  fm  ;
  1967.  
  1968. : WP    endPPC  write_pef  ;
  1969.  
  1970.  
  1971. :ppc_code (DBGR)
  1972.     r12    8 r2    lwz,
  1973.     r12    0 r12    lwz,
  1974.     r12            mtctr,
  1975.     r11    r3        mr,
  1976.     r12            mflr,
  1977.     r12    -4 r17    stwu,
  1978.                 bctrl,
  1979.     r12    r17        lwz,
  1980.     r17    r17 4    addi,
  1981.     r12            mtlr,
  1982.     r3    r11        mr,
  1983. ;ppc_code
  1984.  
  1985.  
  1986. : dbgr                        \ calls the debugger gracefully
  1987.     ['] (dbgr) cfa_adjust 2+  CDP  44  aligned_move
  1988.     44 ++> CDP
  1989.     CDP -> backstop_CDP        \ it's confusing if loads get hoisted here
  1990.     true -> ctr_clobbered?    \ since it is!
  1991. ;            immediate
  1992.  
  1993. : dbgrx                    \ calls the debugger ungracefully - but all regs
  1994.                         \  are intact!
  1995.     0 code,
  1996. ;        immediate
  1997.  
  1998.  
  1999. (*    Straight after the initial entry, we have to set up a legal frame on
  2000.     the system stack.  We make it big enough that we can keep our Mops
  2001.     data stack entirely within this frame.  Thus to the system, it appears
  2002.     that all our Mops machinations are a single procedure execution.
  2003.     The frame size is defined by sys_SP_framesixe in cg1.
  2004.     Now if we're a shared library, our initial entry will have to return
  2005.     to the caller, and nonvolatile regs will have to be saved and
  2006.     restored.  So we save the ones we change here.  We have to allow
  2007.     room for the parameter areas of the system calls we do during
  2008.     setup, so we just leave an arbitrary space of 200 bytes which
  2009.     should be plenty.
  2010. *)
  2011.  
  2012. :ppc_code  (fixSP)
  2013.     r0                        mflr,
  2014.     r0            8    rOSSP    stw,
  2015.     r0                rOSSP    mr,
  2016.     rOSSP
  2017.     sys_SP_framesize negate
  2018.                     rOSSP    stwu,
  2019.     RTOC        20    rOSSP    stw,
  2020.     rMainCode    200    rOSSP    stw,
  2021.     rMainData    204    rOSSP    stw,
  2022.     rModCode    208    rOSSP    stw,
  2023.     rModData    212    rOSSP    stw,
  2024.     rRP            216    rOSSP    stw,
  2025.     rSP            220    rOSSP    stw,
  2026.     rFSP        224    rOSSP    stw,
  2027.     r20            228    rOSSP    stw,
  2028.     r21            232    rOSSP    stw,
  2029.     r22            236    rOSSP    stw,
  2030.     r23            240    rOSSP    stw,
  2031.     r24            244    rOSSP    stw,
  2032.     r25            248    rOSSP    stw,
  2033.     r26            252    rOSSP    stw,
  2034.     r27            256    rOSSP    stw,
  2035.     r28            260    rOSSP    stw,
  2036.     r29            264    rOSSP    stw,
  2037.     r30            268    rOSSP    stw,
  2038.     r31            272    rOSSP    stw,
  2039.  
  2040.     rSP                r0        mr,
  2041.  
  2042. ;ppc_code
  2043.  
  2044. : fix_sys_SP
  2045.     ['] (fixSP)  cfa_adjust 2+  CDP  100  aligned_move
  2046.     100 ++> CDP
  2047.     0 >size: fcstk            \ initially the FP stack isn't set up - this prevents 
  2048.                             \  any stores to it in the initial setup code
  2049. ;        immediate
  2050.  
  2051.  
  2052. :ppc_code (initEnd)
  2053.     RTOC        20    rOSSP    lwz,
  2054.     rMainCode    200    rOSSP    lwz,
  2055.     rMainData    204    rOSSP    lwz,
  2056.     rModCode    208    rOSSP    lwz,
  2057.     rModData    212    rOSSP    lwz,
  2058.     rRP            216    rOSSP    lwz,
  2059.     rSP            220    rOSSP    lwz,
  2060.     rFSP        224    rOSSP    lwz,
  2061.     r20            228    rOSSP    lwz,
  2062.     r21            232    rOSSP    lwz,
  2063.     r22            236    rOSSP    lwz,
  2064.     r23            240    rOSSP    lwz,
  2065.     r24            244    rOSSP    lwz,
  2066.     r25            248    rOSSP    lwz,
  2067.     r26            252    rOSSP    lwz,
  2068.     r27            256    rOSSP    lwz,
  2069.     r28            260    rOSSP    lwz,
  2070.     r29            264    rOSSP    lwz,
  2071.     r30            268    rOSSP    lwz,
  2072.     r31            272    rOSSP    lwz,
  2073.  
  2074.     r3            0            li,            \ return noErr
  2075.  
  2076.     rOSSP        0    rOSSP    lwz,        \ take down frame
  2077.     r0            8    rOSSP    lwz,
  2078.     r0                        mtlr,
  2079.                             blr,
  2080. ;ppc_code
  2081.  
  2082. : init_end
  2083.     ['] (initEnd)  cfa_adjust 2+  CDP  100  aligned_move
  2084.     100 ++> CDP
  2085. ;        immediate
  2086.  
  2087. (*
  2088. : fix_sys_SP
  2089.     $ 7C320B78  code,                    \    mr        SP, sys_SP
  2090.     $ 7C0802A6  code,                    \    mflr    r0
  2091.     $ 90010008  code,                    \    stw        r0,8(sys_SP)
  2092.     sys_SP_framesize negate $ FFFF and
  2093.     $ 94210000  or code,                \    stwu    sys_SP, $-framesize(sys_SP)
  2094.     $ 90410014    code,                    \    stw        RTOC,20(sys_SP)
  2095.     0 >size: fcstk                        \ initially the FP stack isn't set up - this
  2096.                                         \  prevents any stores to it in the initial
  2097.                                         \  setup code
  2098. ;        immediate
  2099. *)
  2100.  
  2101. (*    windup_SL_init takes down the above stack frame, when SETUP has been
  2102.     called as the init routine of a shared library.  As we're returning
  2103.     to the caller, we must restore things properly.
  2104. *)
  2105.  
  2106.  
  2107.  
  2108. \ Some redefinitions, so we can still execute the 68k versions after CROSS:
  2109. : +echox    +echo  ;
  2110. : .errx        .err   ;
  2111. : wordsx    words  ;
  2112. : byex        bye  ;
  2113. : hexx        hex  ;
  2114. : decimalx    decimal  ;
  2115. : cx,        c,  ;
  2116. : allotx    allot  ;
  2117. : reservex    reserve  ;
  2118. : reloc!x    reloc!  ;
  2119. : dumpx        dump  ;
  2120. : endloadx    endload  ;
  2121. : //x        //  ;
  2122. : >namex    3-  -1 traverse  ;
  2123. : displ!x    displ!  ;
  2124. : relocCode,x    relocCode,  ;
  2125. : CDPx        CDP  ;
  2126. : DPx        DP   ;
  2127. : .gsx        .gs  ;
  2128. : zsx        zs  ;
  2129. : 'x        '   ;
  2130.  
  2131.  
  2132.  
  2133. \ These are useful for bug-hunting without having to load the whole PPC image:
  2134.  
  2135. : ROT    rot_cstk  ;        immediate
  2136.  
  2137. : DOWN    3 operands
  2138.         opnd3 push  opnd1 push  opnd2 push  ;        immediate
  2139.  
  2140.  
  2141. string+ s
  2142. file    aFile
  2143.  
  2144. : DFILE            \ disassemble file
  2145.     clear: aFile  -1 stdGet: aFile  0EXIT
  2146.     new: s  open: aFile  OK?
  2147.     aFile readAll: s  close: aFile drop
  2148.     lock: s
  2149.     all: s  over +  2dup swap 200 + swap set_disasm_call_range
  2150.     disasm_rng  cr
  2151.     release: s
  2152.     0 0  set_disasm_call_range
  2153. ;
  2154.